/*
    Licensed under the Apache License, Version 2.0 (the "License"); 
    you may not use this file except in compliance with the License. 
    You may obtain a copy of the License at 
    http://www.apache.org/licenses/LICENSE-2.0 
    Unless required by applicable law or agreed to in writing, software 
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    See the License for the specific language governing permissions and 
    limitations under the License.
      
 */

package jforex.impl;

import java.util.Currency;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.dukascopy.api.IContext;
import com.dukascopy.api.IHistory;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.OfferSide;

/**
 * Object must be updated with latest prices for correct calculation
 */
public class CurrConverter {

    //private Map<Instrument, ITick> prices = new HashMap<Instrument, ITick>();

    protected static Map<Currency, Instrument> pairs = new HashMap<Currency, Instrument>();

    protected static Set<Currency> majors = new HashSet<Currency>();

    static {

        pairs.put(Currency.getInstance("AUD"), Instrument.AUDUSD);
        pairs.put(Currency.getInstance("CAD"), Instrument.USDCAD);
        pairs.put(Currency.getInstance("CHF"), Instrument.USDCHF);
        pairs.put(Currency.getInstance("DKK"), Instrument.USDDKK);
        pairs.put(Currency.getInstance("EUR"), Instrument.EURUSD);
        pairs.put(Currency.getInstance("GBP"), Instrument.GBPUSD);
        pairs.put(Currency.getInstance("HKD"), Instrument.USDHKD);
        pairs.put(Currency.getInstance("JPY"), Instrument.USDJPY);
        pairs.put(Currency.getInstance("MXN"), Instrument.USDMXN);
        pairs.put(Currency.getInstance("NOK"), Instrument.USDNOK);
        pairs.put(Currency.getInstance("NZD"), Instrument.NZDUSD);
        pairs.put(Currency.getInstance("SEK"), Instrument.USDSEK);
        pairs.put(Currency.getInstance("SGD"), Instrument.USDSGD);
        pairs.put(Currency.getInstance("TRY"), Instrument.USDTRY);

        majors.add(Currency.getInstance("USD"));
        majors.add(Currency.getInstance("JPY"));
        majors.add(Currency.getInstance("CHF"));
        majors.add(Currency.getInstance("GBP"));
        majors.add(Currency.getInstance("EUR"));
        majors.add(Currency.getInstance("CAD"));
        majors.add(Currency.getInstance("AUD"));
    }

    private IHistory history = null;

    public CurrConverter(IContext context) {
        this.history = context.getHistory();
    }

    /**
     * 
     * @param moneyToConvert Money which is to be converted  
     * @param targetCurrency the Currency to which conversion is made
     * @param side 
     * @return
     * @throws JFException 
     */
    double convert(double amount, Currency sourceCurrency, Currency targetCurrency) throws JFException {

        // If the same currency, no conversion required.
        if (targetCurrency.equals(sourceCurrency)) {
            return amount;
        }

        //First, convert to USD.
        double dollarValue;
        if (sourceCurrency.equals(Currency.getInstance("USD"))) {
            dollarValue = amount;
        } else {
            Instrument helperSourceCurrencyPair = pairs.get(sourceCurrency);
            if (helperSourceCurrencyPair == null) {
                throw new IllegalArgumentException("Conversion Error: No currency pair found for " + sourceCurrency);
            }

            double helperSourceCurrencyPrice = getLastMarketPrice(helperSourceCurrencyPair, OfferSide.BID);
            if (0 == helperSourceCurrencyPrice)
                return 0;

            dollarValue = helperSourceCurrencyPair.getPrimaryCurrency() == Currency.getInstance("USD") ? amount / helperSourceCurrencyPrice : amount * helperSourceCurrencyPrice;
        }

        // If converting to USD, return USD value...

        if (targetCurrency.equals(Currency.getInstance("USD"))) {
            return dollarValue;
        }

        // Else continue converting...

        Instrument pair = pairs.get(targetCurrency);
        double price = getLastMarketPrice(pair, OfferSide.BID);
        if (0 == price)
            return 0;

        double result = pair.getPrimaryCurrency() == Currency.getInstance("USD") ? dollarValue * price : dollarValue / price;

        return result;
    }

    public double getLastMarketPrice(Instrument pair, OfferSide side) throws JFException {
        double rc = 0;
        ITick tick = history.getLastTick(pair);

        if (tick != null) {
            rc = side == OfferSide.ASK ? tick.getAsk() : tick.getBid();
        }
        return rc;
    }

}
